// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: jaewon

#include "coin1/fastfeed/view/trade_builder.h"

#include <cmath>

#include <glog/logging.h>

#include "coin1/fastfeed/view/view_collection.h"

namespace fastfeed {
namespace view {
namespace detail {

bool BookBuilderParameterHolder::OnBookBuilderParameter(const proto::Feed& feed) {
  if (feed.data_type() != proto::DATA_TYPE_BOOK_BUILDER_PARAMETER) {
    return false;
  }
  CHECK(feed.has_book_builder_param());

  const auto& param = feed.book_builder_param();
  CHECK_GE(param.price_precision(), -10);
  CHECK_LE(param.price_precision(), 15);
  CHECK_GE(param.qty_precision(), -10);
  CHECK_LE(param.qty_precision(), 15);

  price_multiplier_ = pow(10., static_cast<double>(param.price_precision()));
  qty_multiplier_ = pow(10., static_cast<double>(param.qty_precision()));

  // This message does not change book.
  return false;
}

}  // namespace detail

void TradeBuilder::Init(ViewCollection* view_collection) {
  view_collection->SubscribeFeed(
      feed_type(),
      symbol(),
      std::bind(&TradeBuilder::OnFeed, this, std::placeholders::_1));
  view_collection->SubscribeFeed(
      proto::FEED_TYPE_METADATA,
      symbol(),
      std::bind(&TradeBuilder::OnFeed, this, std::placeholders::_1));
  view_collection->SubscribeFeed(
      proto::FEED_TYPE_INDEX,
      symbol(),
      std::bind(&TradeBuilder::OnFeed, this, std::placeholders::_1));
  InitBuilder();
}

bool TradeBuilder::UpdateByProto(const proto::Feed& feed) {
  switch (feed.data_type()) {
    case proto::DATA_TYPE_BOOK_BUILDER_PARAMETER:
      return OnBookBuilderParameter(feed);

    case proto::DATA_TYPE_TRADE:
      return OnTrade(feed);

    case proto::DATA_TYPE_INDEX:
      // hack but reuse.
      return OnIndex(feed);

    default:
      return false;
  }
}

bool TradeBuilder::OnTrade(const proto::Feed& feed) {
  const auto& trade = feed.trade();
  if (trade.qty() == 0) {
    return false;
  }

  UpdateHeader(feed);
  price_ = trade.price();
  qty_ = trade.qty();
  side_ = trade.side();
  has_more_trade_ = feed.feed_continue() == proto::FEED_CONTINUE_YES;
  return true;
}

bool TradeBuilder::OnIndex(const proto::Feed& feed) {
  UpdateHeader(feed);
  price_ = feed.index().price();
  qty_ = 0;
  side_ = proto::TRADE_SIDE_UNKNOWN;
  return true;
}

}  // namespace view
}  // namespace fastfeed
